import { Meta, Source } from '@storybook/addon-docs';

<Meta title="Concepts/Developer/Styling Components" />

## Styling components

Visit the **[Styling handbook](https://github.com/microsoft/fluentui/blob/master/docs/react-v9/contributing/rfcs/react-components/styles-handbook.md)** for a comprehensive styling guide, as this article only introduces basics to get you started quickly.

### Getting started

To style Fluent UI React v9 components `makeStyles` is used. `makeStyles` comes from [Griffel](https://griffel.js.org) a homegrown CSS-in-JS implementation which generates atomic CSS classes.

Get started by simply importing:

```js
import { makeStyles } from '@fluentui/react-components';
```

To style a component, you need to call `makeStyles` in a module scope to create a React hook to be used inside a component.

The `makeStyles` call accepts an object of items where each key is a unique identifier and each value is an object with styles. The call returns an object with classes mapped to these unique identifiers.

{/* TODO: format as <Code /> */}

```jsx
import { makeStyles } from '@fluentui/react-components';

const useStyles = makeStyles({
  root: { color: 'red' },
});

function Component() {
  const classes = useStyles();

  return <div className={classes.root} />;
}
```

### Merging component styles

There are cases where you need to merge classes from multiple `useStyles` calls.

#### ⚠ It is not possible to simply concatenate `useStyles` classes

To properly merge the classes, you need to use `mergeClasses()` function, which performs merge and deduplication of atomic classes generated by `makeStyles()`.

When `mergeClasses()` is called, it merges all classes from first to last - the latter argument overwrites the previous ones (similar to `Object.assign()`).

```jsx
import { makeStyles, mergeClasses } from '@fluentui/react-components';

const useStyles = makeStyles({
  blueBold: {
    color: 'blue',
    fontWeight: 'bold',
  },
  red: {
    color: 'red',
  },
});

function Component() {
  const classes = useStyles();

  const first = mergeClasses(classes.blueBold, classes.red); // { color: 'red', fontWeight: 'bold' }
  const second = mergeClasses(classes.red, classes.blueBold); // { color: 'blue', fontWeight: 'bold' }
}
```

### Mapping props and state to styles

Both `makeStyles` and `mergeClasses` are simple. They are unaware of component state and props. Developers should merge and apply appropriate parts of the `useStyles` call based on their requirements.

```jsx
import { makeStyles } from '@fluentui/react-components';

const useStyles = makeStyles({
  root: { color: 'red' },
  rootPrimary: { color: 'blue' },
});

function Component(props) {
  const classes = useStyles();

  return <div className={mergeClasses('ui-component', classes.root, props.primary && classes.rootPrimary)} />;
}
```

### Applying classes passed from parent

The same approach is used to apply classes passed from parent component. Again, you need to use `mergeClasses()` to properly merge and deduplicate the classes. Note again, that the order of application is important in `mergeClasses()` so that parent classes overwrite component classes.

```jsx
import { mergeClasses } from '@fluentui/react-components';

function Component(props) {
  const classes = useStyles();

  return <div className={mergeClasses(classes.root, props.className /* these definitions have higher precedence */)} />;
}
```

### Applying theme to styles

No matter what theme is used, the component styles are always the same. The only way to change the component styling is through theme tokens which can be used in style values.

```js
import { makeStyles, tokens } from '@fluentui/react-components';

const useStyles = makeStyles({
  root: { display: 'flex' },
  rootPrimary: { color: tokens.colorNeutralForeground3 },
});
```

Those tokens are resolved to CSS variable usages. The `FluentProvider` component is responsible for setting the CSS variables in DOM and changing them when the theme changes. When the theme is switched, only the variables are changed, all styles remain the same.

For more details on, see [Theming](?path=/docs/concepts-developer-theming--page).

### Incorrect usages

This section shows and describes anti-patterns which should never be used.

```js
import { makeStyles, mergeClasses } from '@fluentui/react-components';

const useStyles = makeStyles({
  root: { color: 'red' }, // Do not use colors directly as those are not theme-able. Always use colors from a theme
});

function Component(props) {
  const classes = useStyles();

  const wrongClasses = classes.root + ' ' + props.className; // Never concatenate class strings, always use mergeClasses()
  const wrongClasses2 = mergeClasses(props.className, classes.root); // Incorrect order of classes - as the latest wins, props.className should be last to override the component styles
}
```

### Debugging styles

[Griffel devtools chrome extension](https://chrome.google.com/webstore/detail/griffel-devtools/bejhagjehnpgagkaaeehdpdadmffbigb) can be used to debug style overrides. It shows all griffel styles applied on the currently selected DOM element, including the styles that are overridden in `mergeClasses`.

### Limitations

Griffel's approach to styling comes with certain [limitations](https://griffel.js.org/react/guides/limitations). One of which is the lack of support for [CSS shorthand properties](https://developer.mozilla.org/en-US/docs/Web/CSS/Shorthand_properties). To work around this, Griffel [provides a collection of shorthand functions](https://griffel.js.org/react/api/shorthands) to write css shorthand. Their usage is demonstrated in the next example.

## Overriding FUI component styles

To override an appearance of a FUI component, you use the exactly same approach - You call `makeStyles`/`useStyles` in your code and pass the resulting classes through `props`.

```jsx
import { makeStyles, tokens, shorthands } from '@fluentui/react-components';
import { CallEndRegular } from '@fluentui/react-icons';

const useOverrides = makeStyles({
  button: { color: tokens.colorNeutralForeground3 },
  buttonIcon: {
    ...shorthands.border('1px', 'solid', tokens.colorNeutralStroke1),
  },
  link: { fontWeight: 'bold' },
});

function MyComponent() {
  const overrides = useOverrides();

  return (
    <>
      <Button className={overrides.button} icon={{ className: overrides.buttonIcon, children: <CallEndRegular /> }} />
      <Link className={overrides.link} />
    </>
  );
}
```
